﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Security.AccessControl;
using log4net;

namespace UnitTestsDistributor
{
    [StructLayout(LayoutKind.Sequential)]
    public struct NETRESOURCE
    {
        public int dwScope;
        public int dwType;
        public int dwDisplayType;
        public int dwUsage;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpLocalName;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpRemoteName;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpComment;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpProvider;
        public override String ToString()
        {
            String str = "LocalName: " + lpLocalName + " RemoteName: " + lpRemoteName
                + " Comment: " + lpComment + " lpProvider: " + lpProvider;
            return (str);
        }
    }

    /// <summary>
    /// this class is responsible for mapping shared SVN folder like local network drive and copying 
    /// content to appropriate svn account folder.
    /// The content might be either unit test project output or *.csproj files
    /// </summary>
    public class NetworkDriveMapper
    {
        protected static readonly ILog log = LogManager.GetLogger(typeof(Program));

        [DllImport("mpr.dll")]
        private static extern int WNetAddConnection2A(
            [MarshalAs(UnmanagedType.LPArray)] NETRESOURCE[] lpNetResource,
            [MarshalAs(UnmanagedType.LPStr)] string lpPassword,
            [MarshalAs(UnmanagedType.LPStr)] string UserName,
            int dwFlags);

        /// <summary>
        /// Maps the the shared folder from app.config like local network drive X
        /// </summary>
        public static void MapNetworkDrive()
        {
            NETRESOURCE[] n = new NETRESOURCE[1];
            n[0] = new NETRESOURCE();
            n[0].dwType = 1;
            int dwFlags = 1;
            n[0].lpLocalName = @"X:";
            n[0].lpRemoteName = System.Configuration.ConfigurationSettings.AppSettings["SVNProjectRootFolder"]; 
            n[0].lpProvider = null;
            Console.WriteLine(n[0]);
            int res = WNetAddConnection2A(n, null, null, dwFlags);
            Console.WriteLine("WNetAddConnection3 returned : " + res);
            Console.WriteLine(n[0]);

        }

        /// <summary>
        /// copies the output of the test project to the dedicated folder in the mapped network drive
        /// Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory is used for copying the entire folder content
        /// </summary>
        /// <param name="scrFolderPath">path to the bin folder of the unit test project</param>
        public static void CopyUnitTestFolderContent(string scrFolderPath)
        {
            DriveInfo[] drives = DriveInfo.GetDrives();
            var mappedDrive = from drive in drives
                              where drive.Name.Equals("X:\\")
                              select drive;

            if (mappedDrive.ToList<DriveInfo>().Count != 1)
            {
                log.Fatal("Copying unit tests dlls failed. There is no drive mapped to X.");
                throw new NullReferenceException("Unsuccessful maping");
            }
            
            var svnUser = System.Configuration.ConfigurationSettings.AppSettings["svnUserName"];
            var assembliesTargetPath = System.Configuration.ConfigurationSettings.AppSettings["MSUnitTestsFolderPath"];
            DirectoryInfo dirInfo = new DirectoryInfo(@"X:\" + assembliesTargetPath);
            string targetPath = @"X:\" +  assembliesTargetPath + @"\" + svnUser;
            if (!Directory.Exists(targetPath))
                dirInfo.CreateSubdirectory(svnUser);

            //empty the folder prior copying content
            DirectoryInfo diTarget = new DirectoryInfo(targetPath);
            FileInfo[] files = diTarget.GetFiles();
            foreach (FileInfo file in files)
            {
                file.Delete();
            }
            
            //copy bin folder of this project to the mapped folder (this bin folder will be unit tests project folder
            Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(scrFolderPath, targetPath , true);
        }

        /// <summary>
        /// copies the *.csproj file to the dedicated folder in the mapped network drive
        /// </summary>
        /// <param name="srcProjPath">path to the *.csproj file</param>
        public static void CopyCSharpProjectFile(string srcProjPath)
        {
            DriveInfo[] drives = DriveInfo.GetDrives();
            var mappedDrive = from drive in drives
                              where drive.Name.Equals("X:\\")
                              select drive;

            if (mappedDrive.ToList<DriveInfo>().Count != 1)
            {
                log.Fatal(String.Format("Copying project file {0} failed. There is no drive mapped to X", srcProjPath));
                throw new NullReferenceException("Unsuccessful maping to drive X.");
            }
            var projectFilesTargetPath = System.Configuration.ConfigurationSettings.AppSettings["ProjectsFiles"];
            var svnUser = System.Configuration.ConfigurationSettings.AppSettings["svnUserName"];
            DirectoryInfo dirInfo = new DirectoryInfo(@"X:\" + projectFilesTargetPath);
            string targetPath = @"X:\" + projectFilesTargetPath + @"\" + svnUser;

            if (!Directory.Exists(targetPath))
                dirInfo.CreateSubdirectory(svnUser);

            DirectoryInfo csProjFiles = new DirectoryInfo(targetPath);


            FileInfo fi = new FileInfo(srcProjPath);
            string destinationPath = csProjFiles.FullName + @"\" + fi.Name;
            File.Copy(srcProjPath, destinationPath, true);
           

        }


        static void CopyDirectory(DirectoryInfo source, DirectoryInfo destination)
        {
            if (!destination.Exists)
            {
                destination.Create();
            }

            // Copy all files.
            FileInfo[] files = source.GetFiles();
            foreach (FileInfo file in files)
            {
                file.CopyTo(Path.Combine(destination.FullName,
                    file.Name));
            }

            // Process subdirectories.
            DirectoryInfo[] dirs = source.GetDirectories();
            foreach (DirectoryInfo dir in dirs)
            {
                // Get destination directory.
                string destinationDir = Path.Combine(destination.FullName, dir.Name);

                // Call CopyDirectory() recursively.
                CopyDirectory(dir, new DirectoryInfo(destinationDir));
            }
        }

    }
}
